//数据包发送站对象

import javax.crypto.Mac;
import java.sql.Time;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Random;

/**
 * Station:数据包发送站
 * 生成并发送Frame;
 * 监听MacChannel状态(先听在发,不能边听边发);
 * 控制二进制指数回退[0~2^(i-1)个时间槽];
 * 在固定时间内接收到ACK则说明发送成功,否则发生碰撞;
 * 每次循环开始时都是空闲的时间槽
 */

public class Station {
    //站编号
    int no;
    //等待传输的帧的队列
    Queue<Frame> frameQueue;
    //二进制回退的指数
    private int avoidFrequency;
    //需要回退的次数
    private int avoidToDo;
    //处于回退中,即正在尝试发送一个帧
    private boolean isAvoiding;
    //碰撞次数
    private int collisionNum;
    //记录器
    StationRecorder stationRecorder;

    {
        frameQueue = new ArrayDeque<>();
        avoidFrequency = 0;
        avoidToDo = 0;
        isAvoiding = false;
        collisionNum = 0;
        stationRecorder = new StationRecorder();
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    Station(int no) {
        this.no = no;
    }

//    // 监听信道,不需要监听操作?
//    boolean isTransmittable() {
//    }

    //准备好一个帧需要发送
    //前提:不处于回退状态
    public void readyToSend() {
        frameQueue.peek().setStartSendTime(TimeLine.current);
        startAvoid();
    }

    //尝试发送Frame,
    //若仍处于回退状态,则回退次数减一
    //若回退结束,则发送
    //前提:Channel不处于传输状态
    public void attemptToSend(MacChannel channel) {
        stationRecorder.attemptToSend();
        //若回退次数为0,即回退结束,发送帧,但是此时可能发生冲突
        if (avoidToDo == 0) {
            channel.putFrame(frameQueue.peek());
        } else {
            avoidToDo--;
        }

    }

//    //发送帧,但是不一定会成功
//    private void sendFrame(MacChannel channel) {
//
//    }

    //成功发送了一个帧
    public void sendSuccessfully() {
        setFrameWaitTime();
        frameQueue.poll();
//        if (no == 1) {
//            System.out.println("remove:" + frameQueue.size());
//        }
        //重置回退指数
        avoidFrequency = 0;
        collisionNum = 0;
        isAvoiding = false;
    }

    //刚刚发送的Frame发生碰撞
    public void sendFail() {
        collisionNum++;
        startAvoid();
    }

    //触发二进制指数回退,产生一个回退次数
    private void startAvoid() {
        if (avoidFrequency <= 10) {
            avoidFrequency++;
        }
        avoidToDo = new Random().nextInt((int) Math.pow(2, avoidFrequency));
        isAvoiding = true;
    }

    //向待发送队列添加一个Frame
    public void addFrame(Frame frame) {

        frameQueue.add(frame);
//        if (no == 1) {
//            System.out.println("add:"+frameQueue.size());
//        }
        setFrameWaitNum();
        stationRecorder.getOneFrame();

    }

    //在每个DIFS中执行
    public void routine(MacChannel channel) {
        //若没有正在回退的帧
        if (!isAvoiding) {
            //且待发送队列不为空
            if (!frameQueue.isEmpty()) {
                //开始发送下一个帧
                readyToSend();
            } else {
                //发送队列为空
            }
        } else {
            //若有正在发送的帧
            //尝试发送:处于回退则回退减一;回退结束则发送
            attemptToSend(channel);
        }
    }


    //记录数据函数
    private void setFrameWaitNum() {
        stationRecorder.setFrameWaitNum(frameQueue.size() - 1);
    }

    //第一次发送前的回退时记录
    private void setFrameWaitTime() {
        stationRecorder.sendFrameSuccessfully();
        stationRecorder.setFrameWaitTime(frameQueue.peek().getWaitTime());
    }
}
